package com.linrui.car.service.impl;

import com.linrui.basic.constants.BaseConstants;
import com.linrui.car.domain.CarType;
import com.linrui.car.mapper.CarTypeMapper;
import com.linrui.car.service.ICarTypeService;
import com.linrui.basic.service.impl.BaseServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author wangronggui
 * @since 2022-11-03
 */
@Service
public class CarTypeServiceImpl extends BaseServiceImpl<CarType> implements ICarTypeService {

    @Autowired
    private CarTypeMapper carTypeMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 给主key和副key设置值
     * @param key
     * @param carTypes
     */
    private void setCacheData(String key,List<CarType> carTypes){
        redisTemplate.opsForValue().set(key, carTypes);
        redisTemplate.opsForValue().set(key+"_bak", carTypes);
    }

    @Override
    public List<CarType> tree(Long pid){
        Object o = redisTemplate.opsForValue().get(BaseConstants.CACHE_CARTYPE_IN_REDIS);
        if (Objects.nonNull(o)){
            return (List<CarType>) o;
        }
        //缓存击穿 通过加锁的方式
        synchronized (CarTypeServiceImpl.class){
            o = getCacheData(BaseConstants.CACHE_CARTYPE_IN_REDIS);

            if (Objects.nonNull(o)){
                return (List<CarType>)o;
            }
            List<CarType> carTypes = getCarTypesByLoop(pid);
            // 解决缓存穿透
            setCacheData(BaseConstants.CACHE_CARTYPE_IN_REDIS, carTypes);
            return carTypes;
        }
    }

    /**
     * 获取缓存数据
     * @param key
     * @return
     */
    private List<CarType> getCacheData(String key){
        Object o = redisTemplate.opsForValue().get(key);
        if (Objects.nonNull(o)){
            return (List<CarType>)o;
        }

        o = redisTemplate.opsForValue().get(key+"_bak");

        if (Objects.nonNull(o)){
            redisTemplate.opsForValue().set(key, o);
            return (List<CarType>)o;
        }
        return null;
    }

    @Override
    public void add(CarType carType) {
        super.add(carType);
        redisTemplate.delete(BaseConstants.CACHE_CARTYPE_IN_REDIS);
    }

    @Override
    public void update(CarType carType) {
        super.update(carType);
        redisTemplate.delete(BaseConstants.CACHE_CARTYPE_IN_REDIS);
    }

    @Override
    public void removeById(Serializable id) {
        super.removeById(id);
        redisTemplate.delete(BaseConstants.CACHE_CARTYPE_IN_REDIS);
    }


    private List<CarType> getCarTypesByLoop(Long pid) {
        List<CarType> result = new ArrayList<>();
        List<CarType> allCarTypes = carTypeMapper.loadAll();

        Map<Long, CarType> map = new HashMap<>();
        for (CarType allCarType : allCarTypes) {
            map.put(allCarType.getId(), allCarType);
        }

        for (CarType carType : allCarTypes) {
            if (carType.getPid().longValue() == pid.longValue()){
                result.add(carType);
            }else {
                CarType parent = map.get(carType.getPid());
                parent.getChildren().add(carType);
            }
        }
        return result;
    }

    /**
     * 循环算法
     * 方案一: 时间复杂度 n*n
     * @param pid
     * @return
     */
//    private List<CarType> getCarTypesByLoop(Long pid) {
//        List<CarType> result = new ArrayList<>();
//        List<CarType> allCarTypes = carTypeMapper.loadAll();
//
//        for (CarType carType : allCarTypes) {
//            if (carType.getPid().longValue() == pid.longValue()){
//                result.add(carType);
//            }else {
//                CarType parent = null;
//                for (CarType allCarType : allCarTypes) {
//                    if (carType.getPid().longValue() == allCarType.getId()){
//                        parent = allCarType;
//                        break;
//                    }
//                }
//                parent.getChildren().add(carType);
//            }
//        }
//        return result;
//    }


    /**
     * 递归 要访问n+1次数据库
     * @param pid
     * @return
     */
//    private List<CarType> getCarTypesRecursion(Long pid) {
//        List<CarType> childs = carTypeMapper.loadByPid(pid);
//        if (childs == null){
//            return null;
//        }
//        for (CarType child : childs) {
//            List<CarType> childson = tree(child.getId());
//            child.setChildren(childson);
//        }
//        return childs;
//    }
}
